package sgs.common.utils;

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
/**
 * httpclient工具类
 * @author yaenli
 * @since 2024-05-09
 */
public class HttpClientUtils {

    /**
     * @return
     * @throws KeyManagementException
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     * @deprecated 2024-06-12
     */
    public static CloseableHttpClient getHttpClient_old() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
        // SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
        SSLConnectionSocketFactory scsf = new SSLConnectionSocketFactory(SSLContexts.custom()
                .loadTrustMaterial(null, new TrustSelfSignedStrategy()).setProtocol(SSLConnectionSocketFactory.TLS).build(),
                NoopHostnameVerifier.INSTANCE);
        // 配置连接池
        PoolingHttpClientConnectionManager connectionManager = createConnectionManager();

        CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(scsf).setConnectionManager(connectionManager).build();
        return client;
    }

    /**
     * 获取HttpClient实例
     * @return CloseableHttpClient 实例
     * 注意：调用者应确保资源被正确关闭以避免泄露。
     */
    public static CloseableHttpClient getHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
            SSLContext sslContext = createSSLContext();
            SSLConnectionSocketFactory sslSocketFactory = createSSLConnectionSocketFactory(sslContext);
            PoolingHttpClientConnectionManager connectionManager = createConnectionManager();
            return createHttpClient(sslSocketFactory, connectionManager);
    }
    /**
     * 创建并初始化SSLContext对象，用于配置SSL/TLS协议。
     *
     * SSLContext是Secure Sockets Layer (SSL)和Transport Layer Security (TLS)协议的上下文，
     * 它提供了在应用程序协议中插入SSL/TLS的能力，例如HTTP、FTP、SMTP等。
     *
     * @return 初始化后的SSLContext对象，用于SSL/TLS通信。
     * @throws NoSuchAlgorithmException 如果指定的算法不存在。
     * @throws KeyManagementException 如果密钥管理器工厂初始化失败。
     * @throws KeyStoreException 如果密钥存储区加载或访问失败。
     */
    private static SSLContext createSSLContext() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
                // 客户端证书验证逻辑（信任所有证书，不建议在生产环境中使用）
            }

            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws java.security.cert.CertificateException {
                // 服务器证书验证逻辑（信任所有证书，不建议在生产环境中使用）
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[]{};
            }
        }}, null);
        return sslContext;
    }
    private static SSLConnectionSocketFactory createSSLConnectionSocketFactory(SSLContext sslContext) {
        return new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
    }

    private static PoolingHttpClientConnectionManager createConnectionManager() {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(200); // 最大连接数
        connectionManager.setDefaultMaxPerRoute(20); // 每路由最大连接数
        return connectionManager;
    }
    /**
     * 创建一个自定义配置的CloseableHttpClient实例。
     *
     * 该方法通过传入的SSLConnectionSocketFactory和PoolingHttpClientConnectionManager来定制HTTP客户端的SSL配置和连接管理。
     *
     * @param sslSocketFactory SSL连接套接字工厂，用于配置SSL/TLS连接的特定于应用程序的设置，如证书链和密钥库。
     * @param connectionManager 连接管理器，负责HTTP连接的生命周期管理和复用策略。
     * @return 自定义配置的CloseableHttpClient实例，可用于执行HTTPS请求。
     * 注意：调用者应确保资源被正确关闭以避免泄露。
     */
    public static CloseableHttpClient createHttpClient(SSLConnectionSocketFactory sslSocketFactory, PoolingHttpClientConnectionManager connectionManager) {
        return HttpClients.custom()
                .setSSLSocketFactory(sslSocketFactory)
                .setConnectionManager(connectionManager)
                .build();
    }
}
